package com.inexas.cu.client.register;

import java.util.*;
import com.google.gwt.core.client.*;
import com.google.gwt.validation.client.*;
import com.google.gwt.validation.client.interfaces.*;
import com.inexas.cu.client.mvp.*;
import com.inexas.cu.client.mvp.Observer;

/**
 * The Presentation Model for signing in. SignInPm is subclass of
 * {@link ObservableImpl} so that we can observe changes to any of the properties of
 * the class.
 * 
 */
public class SignInPm extends TupleImpl implements PresentationManager {
	private final IValidator<SignInPm> validator = GWT.create(SignInPm.class);
//	private final IValidator<SignInPm> validator = new ServerValidator<SignInPm>();

	private final PropertyImpl<String> accountName = new PropertyImpl<String>("accountName");

	private final PropertyImpl<String> password = new PropertyImpl<String>("password");

	private final ActuatorImpl signInActuator = new ActuatorImpl("signIn");

	/*
	 * Note about validation. The fields below are a hack to get validation
	 * working in the PM - but this is temporary. The library I'm using seems to
	 * be the implementation of choice (only?) of JSR303. It won't work properly
	 * with PM because we use Properties. There's not too much work to write the
	 * own validation library and gwt-validation has bugs and is not being
	 * updated very quickly so lets reinvent the wheel! In the mean time the
	 * hack.
	 * 
	 * Add a xxxValidate field for each of the properties. Have a listener
	 * update the validation rules. And don't forget to add a getter!
	 */
	@Length(minimum = 3, maximum = 20)
	private String accountNameValidate;
	private String passwordValidate;

	public SignInPm() {
		this(null, null);
	}

	public SignInPm(String accountNameString, String passwordString) {
		super("SignIn");
		// Set the values before we start observing
		accountName.setValue(null, accountNameString);
		password.setValue(null, passwordString);

		// Event Aggregation - Fire an event for a change of the whole PM when
		// any one of it's properties (but not activators) change

		// Add validation and aggregation support...
		accountName.addObserver(new Observer() {
			public void onChanged(Source source, Notification notification) {
				accountNameValidate = accountName.getValue();
				final List<ValidationError> validationErrors = validate("accountNameValidate");
				// !todo The setValidationErrors should fire the notification - no?
				accountName.setValidationErrors(source, validationErrors);
				fire(source, new ValidationChangeNotification(validationErrors));
			}
		});
		this.password.addObserver(new Observer() {
			public void onChanged(Source source, Notification notification) {
				passwordValidate = password.getValue();
				final List<ValidationError> validationErrors = validate("passwordValidate");
				// !todo The setValidationErrors should fire the notification - no?
				password.setValidationErrors(source, validationErrors);
				fire(source, new ValidationChangeNotification(validationErrors));
			}
		});
	}

	private List<ValidationError> validate(String propertyName) {
		final List<ValidationError> result;

		final Set<InvalidConstraint<SignInPm>> constraints = validator.validateProperty(this, propertyName);
		if(constraints.isEmpty()) {
			result = null;
		} else {
			result = new ArrayList<ValidationError>();
			for(final InvalidConstraint<? extends PresentationManager> constraint : constraints) {
				final ValidationError validationError = new ValidationError(constraint);
				result.add(validationError);
			}
		}
		return result;
	}

	public PropertyImpl<String> getAccountName() {
		return accountName;
	}

	public Property<String> getPassword() {
		return password;
	}

	public ActuatorImpl getSignInActuator() {
		return signInActuator;
	}

	public String getAccountNameValidate() {
		return accountNameValidate;
	}

	public String getPasswordValidate() {
		return passwordValidate;
	}

}
